// Copyright Epic Games, Inc. All Rights Reserved.

#pragma once

#include <zencore/logbase.h>
#include <zencore/zencore.h>
#include <zenhttp/httpserver.h>
#include <filesystem>
#include <string>
#include <vector>

namespace zen {

struct ZenUpstreamJupiterConfig
{
	std::string Name;
	std::string Url;
	std::string OAuthUrl;
	std::string OAuthClientId;
	std::string OAuthClientSecret;
	std::string OpenIdProvider;
	std::string AccessToken;
	std::string Namespace;
	std::string DdcNamespace;
};

struct ZenUpstreamZenConfig
{
	std::string				 Name;
	std::vector<std::string> Urls;
	std::vector<std::string> Dns;
};

enum class UpstreamCachePolicy : uint8_t
{
	Disabled  = 0,
	Read	  = 1 << 0,
	Write	  = 1 << 1,
	ReadWrite = Read | Write
};

struct ZenUpstreamCacheConfig
{
	ZenUpstreamJupiterConfig JupiterConfig;
	ZenUpstreamZenConfig	 ZenConfig;
	int32_t					 UpstreamThreadCount		= 4;
	int32_t					 ConnectTimeoutMilliseconds = 5000;
	int32_t					 TimeoutMilliseconds		= 0;
	UpstreamCachePolicy		 CachePolicy				= UpstreamCachePolicy::ReadWrite;
};

struct ZenCacheEvictionPolicy
{
	int32_t MaxDurationSeconds = 24 * 60 * 60;
};

struct ZenProjectStoreEvictionPolicy
{
	int32_t MaxDurationSeconds = 7 * 24 * 60 * 60;
};

struct ZenGcConfig
{
	//	ZenCasEvictionPolicy   Cas;
	ZenCacheEvictionPolicy		  Cache;
	ZenProjectStoreEvictionPolicy ProjectStore;
	int32_t						  MonitorIntervalSeconds			= 30;
	int32_t						  IntervalSeconds					= 0;
	bool						  CollectSmallObjects				= true;
	bool						  Enabled							= true;
	uint64_t					  DiskReserveSize					= 1ul << 28;
	uint64_t					  DiskSizeSoftLimit					= 0;
	int32_t						  LightweightIntervalSeconds		= 0;
	uint64_t					  MinimumFreeDiskSpaceToAllowWrites = 1ul << 28;
	bool						  UseGCV2							= false;
	uint32_t					  CompactBlockUsageThresholdPercent = 90;
	bool						  Verbose							= false;
	bool						  SingleThreaded					= false;
};

struct ZenOpenIdProviderConfig
{
	std::string Name;
	std::string Url;
	std::string ClientId;
};

struct ZenAuthConfig
{
	std::vector<ZenOpenIdProviderConfig> OpenIdProviders;
};

struct ZenObjectStoreConfig
{
	struct BucketConfig
	{
		std::string			  Name;
		std::filesystem::path Directory;
	};

	std::vector<BucketConfig> Buckets;
};

struct ZenStatsConfig
{
	bool		Enabled	   = false;
	std::string StatsdHost = "localhost";
	int			StatsdPort = 8125;
};

struct ZenStructuredCacheConfig
{
	bool	 Enabled				 = true;
	bool	 WriteLogEnabled		 = false;
	bool	 AccessLogEnabled		 = false;
	uint64_t MemCacheSizeThreshold	 = 1 * 1024;
	uint64_t MemTargetFootprintBytes = 512 * 1024 * 1024;
	uint64_t MemTrimIntervalSeconds	 = 60;
	uint64_t MemMaxAgeSeconds		 = gsl::narrow<uint64_t>(std::chrono::seconds(std::chrono::days(1)).count());
};

struct ZenWorkspacesConfig
{
	bool Enabled = false;
};

struct ZenServerOptions
{
	ZenUpstreamCacheConfig	 UpstreamCacheConfig;
	ZenGcConfig				 GcConfig;
	ZenAuthConfig			 AuthConfig;
	ZenObjectStoreConfig	 ObjectStoreConfig;
	zen::HttpServerConfig	 HttpServerConfig;
	ZenStructuredCacheConfig StructuredCacheConfig;
	ZenStatsConfig			 StatsConfig;
	ZenWorkspacesConfig		 WorksSpacesConfig;
	std::filesystem::path	 SystemRootDir;				  // System root directory (used for machine level config)
	std::filesystem::path	 DataDir;					  // Root directory for state (used for testing)
	std::filesystem::path	 ContentDir;				  // Root directory for serving frontend content (experimental)
	std::filesystem::path	 AbsLogFile;				  // Absolute path to main log file
	std::filesystem::path	 ConfigFile;				  // Path to Lua config file
	std::filesystem::path	 BaseSnapshotDir;			  // Path to server state snapshot (will be copied into data dir on start)
	std::string				 ChildId;					  // Id assigned by parent process (used for lifetime management)
	std::string				 LogId;						  // Id for tagging log output
	std::string				 EncryptionKey;				  // 256 bit AES encryption key
	std::string				 EncryptionIV;				  // 128 bit AES initialization vector
	int						 BasePort			= 8558;	  // Service listen port (used for both UDP and TCP)
	int						 OwnerPid			= 0;	  // Parent process id (zero for standalone)
	bool					 InstallService		= false;  // Flag used to initiate service install (temporary)
	bool					 UninstallService	= false;  // Flag used to initiate service uninstall (temporary)
	bool					 IsDebug			= false;
	bool					 IsCleanStart		= false;  // Indicates whether all state should be wiped on startup or not
	bool					 IsPowerCycle		= false;  // When true, the process shuts down immediately after initialization
	bool					 IsTest				= false;
	bool					 IsDedicated		= false;  // Indicates a dedicated/shared instance, with larger resource requirements
	bool					 ShouldCrash		= false;  // Option for testing crash handling
	bool					 IsFirstRun			= false;
	bool					 NoSentry			= false;
	bool					 SentryAllowPII		= false;  // Allow personally identifiable information in sentry crash reports
	bool					 ObjectStoreEnabled = false;
	bool					 NoConsoleOutput	= false;  // Control default use of stdout for diagnostics
	std::string				 Loggers[zen::logging::level::LogLevelCount];
	std::string				 ScrubOptions;
#if ZEN_WITH_TRACE
	std::string TraceHost;	// Host name or IP address to send trace data to
	std::string TraceFile;	// Path of a file to write a trace
#endif
};

void ParseCliOptions(int argc, char* argv[], ZenServerOptions& ServerOptions);

void EmitCentralManifest(const std::filesystem::path& SystemRoot, Oid Identifier, CbObject Manifest, std::filesystem::path ManifestPath);
std::vector<CbObject> ReadAllCentralManifests(const std::filesystem::path& SystemRoot);

}  // namespace zen
